Skip to content

Add GitHub API importer - #204

Merged
pombredanne merged 8 commits into
aboutcode-org:developfrom
sbs2001:github_api_importer
Jul 22, 2020
Merged

pombredanne merged 8 commits into
aboutcode-org:developfrom
sbs2001:github_api_importer

Conversation

@sbs2001

@sbs2001 sbs2001 commented Jun 15, 2020

Copy link
Copy Markdown
Collaborator

TODOs

  • Add Nuget, Maven and Composer package manager's version API

  • Add tests for everything

I will file another separate PR to move all these VersionAPI classes to one separate module.

Signed-off-by: Shivam Sandbhor shivam.sandbhor@gmail.com

@sbs2001
sbs2001 force-pushed the github_api_importer branch 7 times, most recently from 6a76ddf to 144b555 Compare June 17, 2020 06:48
@sbs2001 sbs2001 changed the title [WIP] : Add GitHub API importer Add GitHub API importer Jun 17, 2020

@pombredanne pombredanne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!
Please see my comments inline for your consideration.

Comment thread vulnerabilities/importers/github.py Outdated
Comment thread vulnerabilities/importers/github.py Outdated
Comment thread vulnerabilities/importers/github.py Outdated
Comment thread vulnerabilities/importers/github.py
Comment thread vulnerabilities/importers/github.py Outdated
Comment thread vulnerabilities/importers/github.py
try:
for entry in json_resp['items'][0]['items']:
all_versions.add(entry['catalogEntry']['version'])
# json response for YamlDotNet.Signed triggers this exception

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this means exactly?What about using a cascade of get() instead to understand exactly why there are these key errors? Can you show me the problematic JSON?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you show me the problematic JSON?

This is raising that exception https://api.nuget.org/v3/registration5-semver1/yamldotnet.signed/index.json
All others follow this schema instead https://api.nuget.org/v3/registration5-semver1/sustainsys.saml2/index.json

What about using a cascade of get() instead to understand exactly why there are these key errors?

That can be done, but I thought catching an exception would be more 'pythonic' (EAFP).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That can be done, but I thought catching an exception would be more 'pythonic' (EAFP).

Well, the key is readability and clarity first: here when I read the code in json_resp['items'][0]['items'] I wonder immediately. What if there is no items or this is not a mapping? What is [0]? Is this a list or a mapping with a key 0? if this is a list, what about the other items in that list? and what is this second items about?

Here we could have something instead like that:

for item in json_resp.get('items', []):
    for entry in item.get('items', []):
        ...

When I read it I get these are mapping that return lists and I have no problem to understand the underlying data structure that I do not know about. Otherwise, I feel I need to do quite a bit of effort to read the code and it assumes that I know about the upstream JSON data structure before hand. So EAFP is fine, but it matters more to think about the readability of the code IMHO and how it will resist to future changes in the API and how that will make it easy to debug or not.

This is raising that exception https://api.nuget.org/v3/registration5-semver1/yamldotnet.signed/index.json
All others follow this schema instead https://api.nuget.org/v3/registration5-semver1/sustainsys.saml2/index.json

This is the kind of comment that is needed in the code :)

@sbs2001 sbs2001 Jun 25, 2020

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with everything you said.

I am wondering what's the best answer in this context to the question you asked.

how it will resist to future changes in the API and how that will make it easy to debug or not.

Because in this case, during an occurence of API change the outcome of both approaches EAFP(try-except) and LBYL(get cascade) is same. The code won't crash in an event of API changes in both the cases, resulting in not collecting the data, and that will go unnoticed, unless someone decides to look into the db.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. you can still keep inside your direct items access as all_versions.add(entry['catalogEntry']['version']) so if that part changes if will fail.
  2. we should have tests too
  3. we could think about a very limited subset of "canary"-like tests that are doing live queries on the web and fail if the API changes by returning different data.

Comment thread vulnerabilities/importers/github.py Outdated
all_versions.add(entry['catalogEntry']['version'])
# json response for YamlDotNet.Signed triggers this exception
except KeyError:
return all_versions

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A pass would be clearer... BUT the reason for swallowing the KeyError is what I would like to understand

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea how to handle https://api.nuget.org/v3/registration5-semver1/yamldotnet.signed/index.json which is causing the exception, hence the 'swallowing' of the KeyError

Comment thread vulnerabilities/importers/github.py Outdated

@staticmethod
def composer_url(pkg_name: str) -> str:
vendor, name = pkg_name.split('/')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

always prefer a more robust partition() or rpartition():

>>> vendor, name = pkg_name.split('/')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'pkg_name' is not defined
>>> vendor, _, name = 'foo'.partition('/')
>>> vendor, name
('foo', '')
>>> vendor, _, name = 'foo/bar'.partition('/')
>>> vendor, name
('foo', 'bar')

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

always prefer a more robust partition() or rpartition():

I didn't knew about this function. Thanks.
Robust in the sense it doesn't raise ValueError: not enough values to unpack .

But in this case it makes more sense to me to use split because that would raise an exception and crash out VulnerableCode, instead of ending up writing garbage in the DB.

Comment thread vulnerabilities/importers/github.py Outdated
@sbs2001
sbs2001 requested a review from pombredanne June 18, 2020 09:30
@sbs2001
sbs2001 force-pushed the github_api_importer branch 2 times, most recently from 3d2d6a3 to a51383b Compare June 19, 2020 10:11
@singh1114

Copy link
Copy Markdown
Contributor

LGTM!

@haikoschol
haikoschol self-requested a review June 25, 2020 10:01

@pombredanne pombredanne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! See a few extra nitpickings!

@sbs2001
sbs2001 force-pushed the github_api_importer branch 2 times, most recently from bb93f5d to 28160d8 Compare July 1, 2020 10:20
@sbs2001

sbs2001 commented Jul 16, 2020

Copy link
Copy Markdown
Collaborator Author

We will merge this after the PRs dealing with migrations and changes in data models are done with. It's really painful to refactor these.

@pombredanne pombredanne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All ready to merge... there is one nit on a typo :) 👍

Comment thread vulnerabilities/importers/github.py Outdated
try:
self.gh_token = os.environ["GH_TOKEN"]
except KeyError:
raise GitHubTokenError("Envirnomental variable GH_TOKEN is missing")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Envirnomental -> Environment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed


@staticmethod
def artifact_url(artifact_comps: List[str]) -> str:
base_url = "https://repo.maven.apache.org/maven2/{}"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be you could reuse that function (with a comment you did) instead?
https://github.com/nexB/scancode-toolkit/blob/develop/src/packagedcode/maven.py#L225
This way we can eventually evolve a common maven library out of ScanCode
https://repo.maven.apache.org/maven2 is not the most common base URL too

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's minor though and could wait

sbs2001 added 7 commits July 22, 2020 17:00
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
…ted commas to single inverted commas

Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
@sbs2001
sbs2001 force-pushed the github_api_importer branch from 28160d8 to fb140dc Compare July 22, 2020 11:59
Github API importer was made pre importer_yielder.py era.
This commit adds the seed data to importer_yielder.py

Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
@sbs2001
sbs2001 force-pushed the github_api_importer branch from fb140dc to fe442bf Compare July 22, 2020 12:03

end_cursor = resp["data"]["securityVulnerabilities"]["pageInfo"]["endCursor"]
end_cursor_exp = "after: {}".format('"{}"'.format(end_cursor))
api_data[ecosystem].append(resp)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general it is often better to yield rather than to accumulate in a list, FWIW

return vendor, name

def process_response(self) -> List[Advisory]:
adv_list = []

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above... yielding rather than returning a list is always a good option

@pombredanne pombredanne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a few more comments FYI and this is merging now .
Thanks!

@pombredanne
pombredanne merged commit 94b5e74 into aboutcode-org:develop Jul 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants